package ru.amse.tsyganov.jumleditor.view.activepoints;

import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.GC;

import ru.amse.tsyganov.jumleditor.commands.Command;
import ru.amse.tsyganov.jumleditor.commands.CommandFactory;
import ru.amse.tsyganov.jumleditor.graphicaleditor.Coordinates;
import ru.amse.tsyganov.jumleditor.model.common.Edge;
import ru.amse.tsyganov.jumleditor.model.common.GraphModel;
import ru.amse.tsyganov.jumleditor.model.common.State;
import ru.amse.tsyganov.jumleditor.view.ConnectionPoint;
import ru.amse.tsyganov.jumleditor.view.common.EdgeView;
import ru.amse.tsyganov.jumleditor.view.common.GraphView;
import ru.amse.tsyganov.jumleditor.view.common.StateView;
import ru.amse.tsyganov.jumleditor.view.lines.Line;
import ru.amse.tsyganov.jumleditor.view.lines.LineBuilder;
import ru.amse.tsyganov.jumleditor.view.lines.LinePainter;
import ru.amse.tsyganov.jumleditor.view.lines.SimpleLine;
import ru.amse.tsyganov.jumleditor.view.preferences.Colors;
import ru.amse.tsyganov.jumleditor.view.preferences.Cursors;

public abstract class EdgeActivePoint extends ActivePoint {
	
	private final boolean sourceMoving;
	
	private ConnectionPoint currentPoint = null;
	
	public EdgeActivePoint(boolean sourceMoving) {
		this.sourceMoving = sourceMoving;
	}
	
	public abstract EdgeView<? extends Edge> getEdgeView();
	
	public abstract GraphView<? extends GraphModel> getContainer();
	
	public abstract boolean isClosureAllowed();
	
	@Override
	public final Cursor getCursor() {
		return Cursors.getCursorSizeAll();
	}

	@Override
	public final void paintTempResult(GC gc, Coordinates coordinates) {
		assert gc != null;
		
		gc.setForeground(Colors.getGrayColor());
		gc.setBackground(Colors.getGrayColor());
		
		ConnectionPoint fixedPoint = sourceMoving ? 
			getEdgeView().getTargetConnectionPoint() :
				getEdgeView().getSourceConnectionPoint();
			
		StateView<? extends State> stateView = 
			getContainer().getStateView( 
					getTemporaryActivePointX(), 
					getTemporaryActivePointY());
		
		gc.setBackground(Colors.getBlackColor());
		
		if (currentPoint != null) {
			currentPoint.setSelected(false);
		}
		
		if (stateView == null || (!isClosureAllowed() && fixedPoint.getContainer() == stateView)) {
			LinePainter.drawArrowedLine(gc, coordinates,
					new SimpleLine(
					fixedPoint.getCpX(), 
					fixedPoint.getCpY(),
					getTemporaryActivePointX(), 
					getTemporaryActivePointY()), !sourceMoving);	
		} else {
			currentPoint = stateView.getNearestConnectionPoint(
					getTemporaryActivePointX(), 
					getTemporaryActivePointY());
			
			currentPoint.setSelected(true);
			
			
			Line[] lines = sourceMoving ?
					LineBuilder.getBrokenLine(currentPoint, fixedPoint) :
						LineBuilder.getBrokenLine(fixedPoint, currentPoint);
			
			LinePainter.drawArrowedLine(gc, coordinates, lines);
			currentPoint.paint(gc, coordinates);
		}
		
	}

	@Override
	public final Command createCommandForAction() {
		StateView<? extends State> newStateView = 
			getContainer().getStateView( 
					getTemporaryActivePointX(), 
					getTemporaryActivePointY());
		
		if (newStateView == null) {
			return null;
		}
		
		if (currentPoint != null) {
			currentPoint.setSelected(false);
			currentPoint = null;
		}
		
		ConnectionPoint newSourceConnectionPoint = (sourceMoving) ? 
			newStateView.getNearestConnectionPoint(getTemporaryActivePointX(), getTemporaryActivePointY()) :
					getEdgeView().getSourceConnectionPoint();
				
		ConnectionPoint newTargetConnectionPoint = (!sourceMoving) ? 
				newStateView.getNearestConnectionPoint(getTemporaryActivePointX(), getTemporaryActivePointY()) :
					getEdgeView().getTargetConnectionPoint();
				
		if (newSourceConnectionPoint.getContainer() == 
			newTargetConnectionPoint.getContainer() &&
			!isClosureAllowed()) {
			
			return null;
		}
				
		if (newSourceConnectionPoint == getEdgeView().getSourceConnectionPoint() &&
			newTargetConnectionPoint == getEdgeView().getTargetConnectionPoint()) {
			
			//getEdgeView().initBrokenLine();
			return null;
		}
		
		return CommandFactory.createMoveEdgeCommand(
				getEdgeView(), 
				newSourceConnectionPoint, newTargetConnectionPoint);
	}

	public boolean isSourceMoving() {
		return sourceMoving;
	}

}
